package top.dancun.easuser.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import top.dancun.common.entity.RoleEntity;
import top.dancun.common.entity.UserEntity;
import top.dancun.common.utils.PageUtils;
import top.dancun.common.utils.Query;
import top.dancun.easuser.dao.UserDao;
import top.dancun.easuser.dao.UserRoleDao;
import top.dancun.easuser.entity.PassWordVojo;
import top.dancun.easuser.entity.UserRoleEntity;
import top.dancun.easuser.form.LoginForm;
import top.dancun.easuser.service.UserService;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;


@Service("userService")
public class UserServiceImpl extends ServiceImpl<UserDao, UserEntity> implements UserService {

    @Autowired
    private DataSourceTransactionManager transactionManager;

    @Autowired
    UserRoleDao userRoleDao;


    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        LambdaQueryChainWrapper<UserEntity> queryWrapper = new LambdaQueryChainWrapper<>(this.baseMapper);;
        queryWrapper.like(Objects.nonNull(params.get("username")) && !params.get("username").equals(""),
                UserEntity::getUid,
                params.get("username"));

        IPage<UserEntity> page =  queryWrapper.page(new Query<UserEntity>().getPage(params));

        return new PageUtils(page);
    }

    @Override
    public UserEntity queryByUserName(String username) {
        UserEntity user = this.lambdaQuery().eq(UserEntity::getUid,username).one();
        return user;
    }

    @Override
    public boolean register(LoginForm loginForm) {
        UserEntity user = new UserEntity();
        user.setUid(loginForm.getUsername());
        user.setCreateTime(new Date(System.currentTimeMillis()));
        user.setStatus(1);
        user.setPwd(new Sha256Hash(loginForm.getPassword(), loginForm.getUsername().toString()).toHex());
        return this.save(user);
    }

    @Override
    public UserEntity getUserInfo(String userId) {


        return baseMapper.getUserInfo(userId);
    }

    @Override
    public List<UserEntity> listAllUserAndRole(Wrapper wrapper) {
        return baseMapper.list(wrapper);
    }

    /**
     * 删除所有用户 >> 删除用户相关角色关联
     * @param asList id列表
     */
    @Override
    @Transactional
    public void removeAllByIds(List<String> asList) {
        TransactionStatus status = getTransactionStatus("removeAllByIds");
        try {
            this.removeByIds(asList);
            //删除用户相关角色关联
            LambdaQueryWrapper<UserRoleEntity> wrapper = Wrappers.lambdaQuery();
            wrapper.in(UserRoleEntity::getUserId,asList);
            userRoleDao.delete(wrapper);

        }catch (Exception e){
            //事务回滚
           transactionManager.rollback(status);
        }
    }

    /***
     * 保存用户 》》并保存用户角色
     * @param user
     */
    @Override
    @Transactional
    public void saveUser(UserEntity user) {
        TransactionStatus status = getTransactionStatus("saveUser");
        try{
            user.setCreateTime(new Date());
            user.setPwd(new Sha256Hash(user.getPwd(),user.getUid()).toHex());
            this.save(user);
            for (RoleEntity role : user.getRoles()){
                UserRoleEntity userRole = new UserRoleEntity();
                userRole.setUserId(user.getUid());
                userRole.setRoleId(role.getRoleId());
                userRoleDao.insert(userRole);
            }
        }catch (Exception e){
            transactionManager.rollback(status);
            throw e;
        }

    }


    /***
     * 修改用户 》》删除存用户角色 》》保存用户角色
     * @param user
     */
    @Override
    @Transactional
    public void updateUser(UserEntity user) {
        TransactionStatus status = getTransactionStatus("updateUser");
        try{
            if ("".equals(user.getPwd())){
                user.setPwd(null);
            }else{
                user.setPwd(new Sha256Hash(user.getPwd(),user.getUid()).toHex());
            }
            this.updateById(user);
            LambdaQueryWrapper<UserRoleEntity> wrapper = Wrappers.lambdaQuery();
            wrapper.eq(UserRoleEntity::getUserId,user
                    .getUid());
            userRoleDao.delete(wrapper);
            for (RoleEntity role : user.getRoles()){
                UserRoleEntity userRole = new UserRoleEntity();
                userRole.setUserId(user.getUid());
                userRole.setRoleId(role.getRoleId());
                userRoleDao.insert(userRole);
            }
        }catch (Exception e){
            transactionManager.rollback(status);
            throw e;
        }
    }

    @Override
    public void updatepwd(UserEntity user, PassWordVojo passWordVojo) throws Exception {
        UserEntity user1 = lambdaQuery().eq(UserEntity::getPwd,new Sha256Hash(passWordVojo.password,user.getUid()).toHex()).eq(UserEntity::getUid,user.getUid()).one();
        if (Objects.nonNull(user1)){


            user.setPwd(new Sha256Hash(passWordVojo.newPassword,user.getUid()).toHex());
           lambdaUpdate().set(UserEntity::getPwd,user.getPwd()).eq(UserEntity::getUid,user.getUid()).update();
        }else {
            throw new Exception("密码错误");
        }
    }

    private TransactionStatus getTransactionStatus(String name){
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        // explicitly setting the transaction name is something that can only be done programmatically
        def.setName(name);
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

        TransactionStatus status = transactionManager.getTransaction(def);
        return status;
    }
}